#include "Serial.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h> /* File control definitions */
#include <errno.h>

#include <termios.h>
#include<sys/ioctl.h>
int speed_arr[] = { B38400, B19200, B9600, B4800, B2400, B1200, B300,
                      B38400, B19200, B9600, B4800, B2400, B1200, B300, };
int name_arr[] = {38400,  19200,  9600,  4800,  2400,  1200,  300, 38400,
                                   19200,  9600, 4800, 2400, 1200,  300, };

Serial::Serial(char *dev, int config)
{
    //ctor
    //sprintf(port,"/dev/ttyS%d",comNumber);
    fd = open(dev, O_RDWR  );//|O_NONBLOCK);
    if (fd <0)
    {
        printf("ERROR:OPEN %s",dev);
        exit(1);
    }
    Serial::set_speed(config);
    set_Parity(8,1,'s');
    fcntl(fd, F_SETFL, FNDELAY);
}

 /**
*@brief   设置串口数据位，停止位和效验位
*@param  databits 类型  int 数据位   取值 为 7 或者8
*@param  stopbits 类型  int 停止位   取值为 1 或者2
*@param  parity  类型  int  效验类型 取值为N,E,O,,S
http://blog.chinaunix.net/uid-10747583-id-97303.html
*/
bool Serial::set_Parity(int databits,int stopbits,int parity)
{
       struct termios options;
       if  ( tcgetattr( fd,&options)  !=  0) {
              perror("SetupSerial 1");
              return(false);
       }
       options.c_cflag &= ~CSIZE;
       options.c_lflag  &= ~(ICANON | ECHO | ECHOE | ISIG);  /*Input*/
       options.c_oflag  &= ~OPOST;   /*Output*/

       switch (databits) /*设置数据位数*/
       {
       case 7:
              options.c_cflag |= CS7;
              break;
       case 8:
              options.c_cflag |= CS8;
              break;
       default:
              fprintf(stderr,"Unsupported data size/n"); return (false);
       }
        switch (parity)
        {
               case 'n':
               case 'N':
                      options.c_cflag &= ~PARENB;   /* Clear parity enable */
                      options.c_iflag &= ~INPCK;     /* Enable parity checking */
                      break;
               case 'o':
               case 'O':
                      options.c_cflag |= (PARODD | PARENB); /* 设置为奇效验*/
                      options.c_iflag |= INPCK;             /* Disnable parity checking */
                      break;
               case 'e':
               case 'E':
                      options.c_cflag |= PARENB;     /* Enable parity */
                      options.c_cflag &= ~PARODD;   /* 转换为偶效验*/
                      options.c_iflag |= INPCK;       /* Disnable parity checking */
                      break;
               case 'S':
               case 's':  /*as no parity*/
                   options.c_cflag &= ~PARENB;
                      options.c_cflag &= ~CSTOPB;break;
               default:
                      fprintf(stderr,"Unsupported parity/n");
                      return (false);
               }
        /* 设置停止位*/
        switch (stopbits)
        {
               case 1:
                      options.c_cflag &= ~CSTOPB;
                      break;
               case 2:
                      options.c_cflag |= CSTOPB;
                  break;
               default:
                       fprintf(stderr,"Unsupported stop bits/n");
                       return (false);
        }
        /* Set input parity option */
        if (parity != 'n')
               options.c_iflag |= INPCK;
        tcflush(fd,TCIFLUSH);
        options.c_cc[VTIME] = 5; /* 设置超时0 seconds*/
        options.c_cc[VMIN] = 0; /* define the minimum bytes data to be readed*/
        //http://www.cnblogs.com/datetree/archive/2013/02/25/2931938.html
        if (tcsetattr(fd,TCSANOW,&options) != 0)
        {
               perror("SetupSerial 3");
               return (false);
        }
        return true;
}
bool Serial::ReadSerial(char *msg,int length)
{
   int t=read(fd,msg,length);
   if(t==-1)
    return false;
    msg[t]='\0';
   return true;
}
bool Serial::set_speed(int baudRate)
{
        int   i;
       int   status;
       struct termios   Opt;
       tcgetattr(fd, &Opt);
       for ( i= 0;  i < sizeof(speed_arr) / sizeof(int);  i++) {
              if  (baudRate == name_arr[i]) {
                     tcflush(fd, TCIOFLUSH);
                     cfsetispeed(&Opt, speed_arr[i]);
                     cfsetospeed(&Opt, speed_arr[i]);
                     status = tcsetattr(fd, TCSANOW, &Opt);
                     if  (status != 0) {
                            perror("tcsetattr fd");
                            return false;
                     }
                     tcflush(fd,TCIOFLUSH);
              }
       }
    return true;
}
int Serial::available()
{
    int leftBytes;
    ioctl(fd,FIONREAD,&leftBytes);
    return leftBytes;
}
bool Serial::WriteSerial(char *msg, int length)
{
    int t=write(fd,msg,length);
    if(t==-1)
        return false;
    return true;
}
Serial::~Serial()
{
    //dtor
    close(fd);
}
